from django.http import JsonResponse
from drf_spectacular.utils import extend_schema
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.mixins import (CreateModelMixin, ListModelMixin,
                                   RetrieveModelMixin, UpdateModelMixin)
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from utils.autoschema import AutoDocSchema
from utils.decorators import activities_logging, error_response, request_data, check_group_permission

from django.db.models import Q

import backend.cews.services.StockItemService as StockItemService
import backend.cews.services.LogService as LogService
from backend.cews.models import Log, StockItem, StockItemReplacement

from .serializers import (AssetSerializer, EquipmentLevelRelationSerializer,
                          StockItemRelationSerializer,
                          StockItemReplacementSerializer, StockItemSerializer,
                          SystemSerializer, WorkgroupSerializer,StockItemWithChildSerializer,
                          StockCodeSerializer,StockItemObsolescenceSerializer)
import json

class StockItemViewSet(
    RetrieveModelMixin,
    ListModelMixin,
    UpdateModelMixin,
    GenericViewSet,
    CreateModelMixin
):
    serializer_class = StockItemSerializer
    queryset = StockItem.objects.all().filter(deleted=False)

    @extend_schema(
        responses={200: StockItemSerializer()},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="create_stock_item", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "stock_code",
            "car",
            "workgroup",
            "system",
            "short_description",
            "description",
            "date_code",
            "sw_ver",
            "hw_ver",
            "obsolescence",
            "asset_id",
            "equipment_class",
            "lv1",
            "lv2",
            "lv3",
            "lv4",
            "lv5",
            "parent_stock_item_stock_code",
            "global_regular_cycle_month",
        ],
        types={
            "stock_code": str,
            "car": str,
            "workgroup": str,
            "system": str,
            "short_description": str,
            "description": str,
            "date_code": str,
            "sw_ver": str,
            "hw_ver": str,
            "obsolescence": int,
            "asset_id": str,
            "equipment_class": str,
            "lv1": str,
            "lv2": str,
            "lv3": str,
            "lv4": str,
            "lv5": str,
            "parent_stock_item_stock_code": str,
            "global_regular_cycle_month": int,
        },
        optional=[
            "description",
            "date_code",
            "sw_ver",
            "hw_ver",
            "obsolescence",
            "lv5",
            "parent_stock_item_stock_code",
            "asset_id",
            "global_regular_cycle_month",
        ]
    )
    @error_response()
    @check_group_permission('add_stockitem')
    def create_stock_item(
        self,
        request,
        stock_code,
        car,
        workgroup,
        system,
        short_description,
        equipment_class,
        obsolescence,
        lv1,
        lv2,
        lv3,
        lv4,
        global_regular_cycle_month,
        asset_id="",
        description="",
        date_code="",
        sw_ver="",
        hw_ver="",
        lv5="",
        parent_stock_item_stock_code="",
    ):
        '''
        desc: Create stock item
        json:
            stock_code: string
            car: string
            workgroup: string
            system: string
            short_description: string
            description:
                type: string
                required: False

            date_code:
                type: string
                required: False

            sw_ver:
                type: string
                required: False

            hw_ver:
                type: string
                required: False

            asset_id:
                type: string
                required: False

            equipment_class: string
            lv1: string
            lv2: string
            lv3: string
            lv4: string
            lv5:
                type: string
                required: False

            parent_stock_item_stock_code:
                type: string
                required: False

            obsolescence: int
            global_regular_cycle_month: int
        '''

        new_stock_item, parent_stock_item = \
            StockItemService.save_stock_item(
                stock_code,
                car,
                workgroup,
                system,
                short_description,
                description,
                date_code,
                sw_ver,
                hw_ver,
                obsolescence,
                equipment_class,
                lv1,
                lv2,
                lv3,
                lv4,
                lv5,
                asset_id,
                request,
                global_regular_cycle_month,
            )

        serializer = StockItemSerializer(new_stock_item)
        return Response(status=status.HTTP_200_OK, data=serializer.data)

    @extend_schema(
        responses={200: StockItemSerializer()},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="update_stock_item", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "stock_code",
            "car",
            "workgroup",
            "system",
            "short_description",
            "description",
            "date_code",
            "sw_ver",
            "hw_ver",
            "obsolescence",
            "asset_id",
            "equipment_class",
            "lv1",
            "lv2",
            "lv3",
            "lv4",
            "lv5",
            "parent_stock_item_stock_code",
        ],
        types={
            "stock_code": str,
            "car": str,
            "workgroup": str,
            "system": str,
            "short_description": str,
            "description": str,
            "date_code": str,
            "sw_ver": str,
            "hw_ver": str,
            "obsolescence": int,
            "lv1": str,
            "lv2": str,
            "lv3": str,
            "lv4": str,
            "lv5": str,
            "parent_stock_item_stock_code": str
        },
        optional=[
            "description",
            "date_code",
            "sw_ver",
            "hw_ver",
            "obsolescence",
            "lv5",
            "parent_stock_item_stock_code",
            'car',
            'asset_id'
        ]
    )
    @error_response()
    @check_group_permission('change_stockitem')
    def update_stock_item(
        self,
        request,
        stock_code,
        workgroup,
        system,
        short_description,
        equipment_class,
        lv1,
        lv2,
        lv3,
        lv4,
        asset_id="",
        car='',
        description="",
        date_code="",
        sw_ver="",
        hw_ver="",
        lv5="",
        obsolescence=0,
        parent_stock_item_stock_code="",
    ):
        '''
        desc: Create stock item
        json:
            stock_code: string
            car: string
            workgroup: string
            system: string
            short_description: string
            description:
                type: string
                required: False

            date_code:
                type: string
                required: False

            sw_ver:
                type: string
                required: False

            hw_ver:
                type: string
                required: False

            asset_id:
                type: string
                required: False

            equipment_class: string
            lv1: string
            lv2: string
            lv3: string
            lv4: string
            lv5:
                type: string
                required: False

            parent_stock_item_stock_code:
                type: string
                required: False
        '''

        new_stock_item, parent_stock_item = \
            StockItemService.save_stock_item(
                stock_code,
                car,
                workgroup,
                system,
                short_description,
                description,
                date_code,
                sw_ver,
                hw_ver,
                obsolescence,
                equipment_class,
                lv1,
                lv2,
                lv3,
                lv4,
                lv5,
                asset_id,
                request
            )

        serializer = StockItemSerializer(new_stock_item)
        return Response(status=status.HTTP_200_OK, data=serializer.data)

    @extend_schema(
        responses={200: StockItemRelationSerializer(many=True)},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="get_child_stock_items", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "parent_stock_item_stock_code",
        ],
        types={
            "parent_stock_item_stock_code": str
        }
    )
    def get_child_stock_items(
        self,
        request,
        parent_stock_item_stock_code="",
    ):
        '''
        desc: Get child stock items
        json:
            parent_stock_item_stock_code: string
        '''

        child_stock_items = StockItemService.get_child_stock_item(
            parent_stock_item_stock_code
        )

        serializer = StockItemRelationSerializer(child_stock_items, many=True)
        return Response(status=status.HTTP_200_OK, data=serializer.data)

    @extend_schema(
        responses={200: StockItemSerializer(many=True)},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="get_all_lv5_stock_code", schema=AutoDocSchema()
    )
    def get_all_lv5_stock_code(
        self,
        request
    ):
        '''
        desc: Get all lv5 stock code from stock item master.
        '''
        serializer = StockItemSerializer(
            StockItemService.get_all_lv5_stock_code(),
            many=True
        )

        return Response(status=status.HTTP_200_OK, data=serializer.data)

    @extend_schema(
        responses={200: StockItemSerializer()},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="assign_stock_item_child", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "parent_stock_item_stock_code",
            "stock_code",
        ]
    )
    @error_response()
    @check_group_permission('add_stockitemrelation')
    def assign_stock_item_child(
        self,
        request,
        parent_stock_item_stock_code,
        stock_code
    ):
        '''
        desc: Assign stock item child to parent.
        json:
            parent_stock_item_stock_code: string
            stock_code: string
        '''
        response = {
            "code": 0,
            "message": "Failed to assign child."
        }

        child_stock_item = StockItemService.assign_stock_item_child(
            stock_code,
            parent_stock_item_stock_code,
            request
        )

        serializer = StockItemSerializer(
            child_stock_item
        )

        response = serializer.data

        return Response(status=status.HTTP_200_OK, data=response)

    # @activities_logging(
    #     log_type=Log.LogType.DEFITMENT,
    #     action=Log.ActionType.DELETE,
    #     description="Stock item defitment"
    # )
    @action(
        detail=False, methods=["POST"],
        url_name="remove_stock_item_child", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "parent_stock_item_stock_code",
            "stock_code",
            "sequence"
        ]
    )
    @error_response()
    @check_group_permission('delete_stockitemrelation')
    def remove_stock_item_child(
        self,
        request,
        parent_stock_item_stock_code,
        stock_code,
        sequence
    ):
        '''
        desc: Remove stock item child from parent.
        json:
            parent_stock_item_stock_code: string
            stock_code: string
        responses:
            "200":
                code: number
                message: string
        '''
        response = {}
        try:
            if StockItemService.remove_stock_item_child(
                stock_code,
                parent_stock_item_stock_code,
                sequence,
                request
            ):
                response = {
                    "code": 1,
                    "message": "Success to remove child."
                }
            return Response(status=status.HTTP_200_OK, data=response)

        except ValueError as ex:
            return Response(status=status.HTTP_400_BAD_REQUEST, data={
                "code": 0,
                "message": str(ex)
            })

    # @activities_logging(
    #     log_type=Log.LogType.REORDER,
    #     action=Log.ActionType.UPDATE,
    #     description="Stock item sequence re-order"
    # )
    @action(
        detail=False, methods=["POST"],
        url_name="reorder_stock_item_child", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "sequence_json",
            "parent_stock_code"
        ]
    )
    @error_response()
    @check_group_permission('change_stockitemrelation')
    def reorder_stock_item_child(
        self,
        request,
        parent_stock_code,
        sequence_json
    ):
        '''
        desc: Re-order stock item child.
        json:
            sequence_json: object
            parent_stock_code: string
        responses:
            "200":
                code: number
                message: string
        '''
        response = {
            "code": 0,
            "message": "Failed to re-order child."
        }

        if StockItemService.reorder_stock_item_child(
            parent_stock_code,
            sequence_json,
            request
        ):
            response = {
                "code": 1,
                "message": "Success to re-order child."
            }

        return Response(status=status.HTTP_200_OK, data=response)

    @extend_schema(
        responses={200: StockItemReplacementSerializer(many=True)},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="get_hard_time_replacement", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "stock_code"
        ]
    )
    def get_hard_time_replacement(
        self,
        request,
        stock_code
    ):
        '''
        desc: Get hard time replacement from stock item.
        json:
            stock_code: string
        '''
        response = StockItemReplacementSerializer(
            StockItemService.get_hard_time_replacement(stock_code),
            many=True
        )

        return Response(status=status.HTTP_200_OK, data=response.data)

    @action(
        detail=False, methods=["POST"],
        url_name="update_replacement_task_period", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "id",
            "period",
            "component",
        ]
    )
    @error_response()
    @check_group_permission('change_stockitemreplacement')
    def update_replacement_task_period(
        self,
        request,
        id,
        period,
        component
    ):
        '''
        desc: Update replacement task period for stock item.
        json:
            id: number
            period: number
        '''
        response = {
            "code": 0,
            "message": "Failed to update replacement task."
        }

        if StockItemService.update_replacement_task_period(
            id,
            period,
            component,
            request
        ):
            response = {
                "code": 1,
                "message": "Replacement task updated."
            }

        return Response(status=status.HTTP_200_OK, data=response)

    @action(
        detail=False, methods=["POST"],
        url_name="create_replacement_task", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "stock_code",
            "component",
            "period",
        ]
    )
    @error_response()
    @check_group_permission('add_stockitemreplacement')
    def create_replacement_task(
        self,
        request,
        stock_code,
        component,
        period
    ):
        '''
        desc: Create replacement task for stock item.
        json:
            stock_code: string
            component: string
            period: number
        '''
        try:
            if StockItemService.create_replacement_task(
                stock_code,
                component,
                period,
                request
            ):
                return Response(status=status.HTTP_200_OK, data={
                    'code': 1,
                    'message': 'Replacement task created'
                })

            return Response(status=status.HTTP_200_OK, data={
                'code': 0,
                'message': 'Failed to create replacement task'
            })
        except Exception as ex:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'code': 0,
                    "message": str(ex)
                }
            )

    @extend_schema(
        responses={200: StockItemSerializer()},
    )
    @action(
        detail=False, methods=["POST"],
        url_name="get_stock_item", schema=AutoDocSchema()
    )
    @request_data(keys=["stock_code"])
    def get_stock_item(
        self,
        request,
        stock_code,
    ):
        '''
        desc: Get stock item by stock code.
        json:
            stock_code: string
        '''
        try:
            response = StockItemSerializer(
                StockItemService.get_stock_item(
                    stock_code
                )
            )

            return Response(status=status.HTTP_200_OK, data=response.data)
        except StockItem.DoesNotExist as ex:
            return JsonResponse(
                data={
                    'code': 0,
                    'message': str(ex),
                },
                status=400
            )

    @extend_schema(
        responses={
            200: AssetSerializer(many=True)
        }
    )
    @action(
        detail=False, methods=["POST"], url_name="get_level_options",
        schema=AutoDocSchema()
    )
    def get_level_options(
        self,
        request,
    ):
        '''
            desc: Get level options
        '''
        serializer = AssetSerializer(
            StockItemService.get_level_options(),
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )

    @extend_schema(
        responses={
            200: SystemSerializer(many=True)
        }
    )
    @action(
        detail=False, methods=["POST"], url_name="get_system_options",
        schema=AutoDocSchema()
    )
    def get_system_options(
        self,
        request,
    ):
        '''
            desc: Get system options
        '''
        serializer = SystemSerializer(
            StockItemService.get_system_options(),
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )

    @extend_schema(
        responses={
            200: WorkgroupSerializer(many=True)
        }
    )
    @action(
        detail=False, methods=["POST"], url_name="get_workgroup_options",
        schema=AutoDocSchema()
    )
    def get_workgroup_options(
        self,
        request,
    ):
        '''
            desc: Get workgroup options
        '''
        serializer = WorkgroupSerializer(
            StockItemService.get_workgroup_options(),
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )

    @extend_schema(
        responses={
            200: EquipmentLevelRelationSerializer(many=True)
        }
    )
    @action(
        detail=False, methods=["POST"], url_name="get_equipment_level",
        schema=AutoDocSchema()
    )
    @request_data(
        keys=["equipment_class"],
        types={"equipment_class": str}
    )
    def get_equipment_level(
        self,
        request,
        equipment_class
    ):
        '''
            desc: Get equipment level
            json:
                equipment_class: string
        '''
        serializer = EquipmentLevelRelationSerializer(
            StockItemService.get_equipment_level(
                equipment_class
            ),
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )

    @action(
        detail=False, methods=["POST"],
        url_name="delete_task", schema=AutoDocSchema()
    )
    @request_data(
        keys=["task_id"]
    )
    @error_response()
    @check_group_permission('delete_stockitemtask')
    def delete_task(
        self,
        request,
        task_id
    ):
        '''
        desc: Soft delete task from stock item.
        json:
            task_id: number
        '''
        response = {
            "code": 0,
            "message": "Failed to delete task."
        }

        if StockItemService.delete_task(
            task_id
        ):
            response = {
                "code": 1,
                "message": "Task deleted."
            }

        return Response(status=status.HTTP_200_OK, data=response)


    @action(detail=False, methods=['post'], schema=AutoDocSchema())
    @request_data(keys=['id'])
    @error_response()
    @check_group_permission('delete_stockitemreplacement')
    def delete_replacement(self,request,id):
        '''
            desc: delete stock item replacement by its id
        '''

        StockItemService.delete_part_replacement(id, request)

        return JsonResponse(data={'code':1,'message':'success'},status=200)


    @action(detail=False, methods=['get'], schema=AutoDocSchema())
    @error_response()
    def get_stock_item_with_num_of_child(self,request):
        '''
            get stock item with numbers of child
        '''
        serializer=StockItemWithChildSerializer(
            StockItem.objects.all().filter(deleted=False)
            ,
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data

        )

    @action(detail=False, methods=['post'], schema=AutoDocSchema())
    @request_data(keys=['stock_code', 'system', 'description'])
    @error_response()
    def get_stock_item_with_num_of_child_filter(self, request, stock_code, system, description):
        '''
            get stock item with numbers of child by stock_code and system and description
        '''
        query = Q()
        if stock_code:
            query &= Q(stock_code__icontains=stock_code)
        if system:
            query &= Q(system__icontains=system)
        if description:
            query &= Q(description__icontains=description)
        serializer=StockItemWithChildSerializer(
            StockItem.objects.all().filter(deleted=False).filter(query)
            ,
            many=True
        )
        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )


    @action(detail=False, methods=['get'], schema=AutoDocSchema())
    @error_response()
    def get_stock_item_obsolescence(self,request):
        '''
            get stock item with numbers of child
        '''
        serializer=StockItemObsolescenceSerializer(
            StockItem.objects.all().filter(deleted=False, obsolescence=1)
           ,
            many=True
        )
        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data
        )


    @action(
        detail=False, methods=["DELETE"],
        url_name="soft_delete_stock_item", schema=AutoDocSchema()
    )
    @request_data(
        keys=[
            "id"
        ]
    )
    @error_response()
    @check_group_permission('delete_stockitem')
    def soft_delete_stock_item(
        self,
        request,
        id
    ):

        if StockItemService.soft_delete_stock_item(
            id,
            request.user
        ):
            response = {
                "code": 1,
                "message": "Success delete part"
            }

        return Response(status=status.HTTP_200_OK, data=response)

    @action(detail=False, methods=['get'], schema=AutoDocSchema())
    @error_response()
    def get_all_stock_code(self,request,):

        serializer=StockCodeSerializer(
            # PartsService.get_parts_with_num_of_child()
            StockItem.objects.all().filter(deleted=False)
            ,
            many=True
        )

        return Response(
            status=status.HTTP_200_OK,
            data=serializer.data

        )

    @action(detail=False, methods=['get'], schema=AutoDocSchema())
    @error_response()
    def get_extra_stock_master_list_edoc_completion_rate(self,request):

        edoc_completion_rate_dict = StockItemService.get_extra_stock_master_list_edoc_completion_rate()

        return Response(
            status=status.HTTP_200_OK,
            data=edoc_completion_rate_dict
        )


    @action(detail=False, methods=['get'], schema=AutoDocSchema())
    @error_response()
    def get_extra_stock_master_list_sw_ver_completion_rate(self,request):

        edoc_completion_rate_dict = StockItemService.get_extra_stock_master_list_sw_ver_completion_rate()

        return Response(
            status=status.HTTP_200_OK,
            data=edoc_completion_rate_dict
        )
